import { newArrayProto } from "./array"

class Observer{
  constructor(data){
    //个数据加了一个标识 ，如果数据有__ob__,说明数据被代理了
    Object.defineProperty(data,'__ob__',{
      value:this,
      enumerable:false
    })

    if(Array.isArray(data)){
      // 数组遍历，性能浪费严重
      // 重写数组中的7个变异方法方法 可以修改数组本身
      // 需要保留数组原有的特性，重写部分方法
      data.__proto__ = newArrayProto  


      this.observeArray(data) // 数组中的对象可以被监控到


    }else{
      // Object.defineProperty只能劫持已存在的属性 （vue2会为此单独写一些api $set ￥delete）
      this.walk(data)
    }
  }
  // 遍历对象
  walk(data){
    // "重新定义"属性
    Object.keys(data).forEach(
      key=>{
        defineReactive(data,key,data[key])
      }
    )
  }
  observeArray(data){
    data.forEach(item=>{
      observe(item)
    })
  }
}

export function defineReactive(target,key,value){ //闭包 属性劫持
  observe(value)
  Object.defineProperty(target,key,{
    get(){ //取值的时候会执行get
      return value
    },
    set(newValue){ // 修改的时候 会执行set
      if(newValue === value) return
      observe(newValue)
      value = newValue
    }
  })

}


export function observe(data){

  //对这个对象进行行劫持
  if(typeof data !="object" || data == null){
    return //只对对象进行劫持
  }

  if(data.__ob__ instanceof Observer){
    return data.__data__
  }

  // 如果一个对象被劫持了，就不需要被劫持了（要判断一个对象是否被劫持哦，可以增添一个实例，用实例来判断是否被劫持过）
  return new Observer(data)
}